﻿/*
·´`·.¸.»------------------------------------------------------------ë·´`·.¸.»
        File: LineDetection.cs
        Project: Themaopdracht 7
        Author: Felix Mann & Thierry Gerritse

        Description:
        Checks a bitmap for black pixels at known places to determine which letter is contained within the image.
·´`·.¸.»------------------------------------------------------------ë·´`·.¸.»
*/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Windows.Forms;
using THO7_Team8.Filters.OCR;

namespace THO7_Team8
{
    class NumberPlateLetterDetection : VisionAlgorithm
    {
        private double hoogtefactor;
        private double breedtefactor;
        private Bitmap _sourceImage;
        private LetterDetectionPoint[] theLetterDetectionPoints;
        private DetectableCharacter[] theDetectableCharacters;

        public NumberPlateLetterDetection(String name) : base(name){
        }

        public override System.Drawing.Bitmap DoAlgorithm(System.Drawing.Bitmap sourceImage)
        {
            //FliX: We calculate the approximate position of the pixels based on the original image size. 
            hoogtefactor = (sourceImage.Height / 26);
            breedtefactor = (sourceImage.Width / 16);
            _sourceImage = sourceImage;

            //FliX: The detection points are labled 'A' to 'S' 
            theLetterDetectionPoints = new LetterDetectionPoint[18] {
                new LetterDetectionPoint('A', 2, 2), 
                new LetterDetectionPoint('B', 9, 2),
                new LetterDetectionPoint('C', 15, 2),
                new LetterDetectionPoint('D', 5, 4),
                new LetterDetectionPoint('E', 2, 7),
                new LetterDetectionPoint('F', 15, 7),
                new LetterDetectionPoint('G', 11, 11),
                new LetterDetectionPoint('H', 11, 15),
                new LetterDetectionPoint('I', 9, 19),
                new LetterDetectionPoint('J', 5, 21),
                new LetterDetectionPoint('K', 3, 25),
                new LetterDetectionPoint('L', 14, 25),
                new LetterDetectionPoint('M', 2, 18),
                new LetterDetectionPoint('O', 9, 25),
                new LetterDetectionPoint('P', 12, 20),
                new LetterDetectionPoint('Q', 11, 6),
                new LetterDetectionPoint('R', 2, 12),
                new LetterDetectionPoint('S', 2, 12)
            };
 
            //FliX: This is the array of letters that we know and the points that they can be recognised at.
            theDetectableCharacters = new DetectableCharacter[25]{
                new DetectableCharacter('B', "ABDEFHKLMRS"),
                new DetectableCharacter('D', "ABDEFKMRS"),
                new DetectableCharacter('F', "ABCDEHKMRS"),
                new DetectableCharacter('G', "BDEKLMPRS"),
                new DetectableCharacter('H', "ACEFHIKLMPRS"),
                new DetectableCharacter('J', "CFKLOP"),
                new DetectableCharacter('K', "AEIKMQRS"),
                new DetectableCharacter('L', "AEKMR"),
                new DetectableCharacter('N', "ACDEFIKLMPRS"),
                new DetectableCharacter('P', "ABCDEFHKMRS"),
                new DetectableCharacter('R', "ADEIJKLMPRS"),
                new DetectableCharacter('R', "ABEGHIKLMPQRS"),//Hmmmmmmm, dit is een rare R
                new DetectableCharacter('S', "BCDEHKLRS"),
                new DetectableCharacter('X', "ADFGHILP"), //ACDFGHIJKLP
                new DetectableCharacter('V', "ADEFIOP"), 
                new DetectableCharacter('Z', "ABCDGJKQ"),
                new DetectableCharacter('0', "BCDEJKLMRS"),
                new DetectableCharacter('1', "BCDEFGHIJKLMOPQRS"), //This character is very narrow, when stretched it WILL be at almost every point that we check!
                new DetectableCharacter('2', "ABCDFHIKP"),
                new DetectableCharacter('3', "ABCDHKL"),
                new DetectableCharacter('5', "ABDEHKORS"),
                new DetectableCharacter('6', "BHIJKLMP"),
                new DetectableCharacter('7', "ABCDFGHIOP"),
                new DetectableCharacter('8', "BCDEHIJKRS"),
                new DetectableCharacter('9', "BCDEIJLMPRS")
            };

            String detectedPoints = "";
           
            foreach(LetterDetectionPoint ldp in theLetterDetectionPoints){
                if(pixelIsBlack(ldp.getXPos(), ldp.getYPos())){
                    detectedPoints += ldp.getChar();
                    ldp.setDetected();
                }
            }

            Console.WriteLine("We found black pixels at the following positions: " + detectedPoints);
            if (detectedPoints.Length <= 4)
            {
                MessageBox.Show("We are very uncertain that the image is of adequate quality. Maybe we should pimp it up?");
            }
            determineFoundCharacter(detectedPoints, theDetectableCharacters); // Check for the most probably candidate
            return sourceImage;
        }

        private char determineFoundCharacter(String foundLetters, DetectableCharacter[] detectableCharacters)
        {
            Char possibleCandidate = 'O';
            int confidence = 0;
            foreach (DetectableCharacter dc in detectableCharacters)
            {
                if (lettersPresentInString(dc.getDetectionPoints(), foundLetters))
                {
                    if (dc.getDetectionPoints().Length > confidence)
                    {
                        possibleCandidate = dc.getChar();
                        confidence = dc.getDetectionPoints().Length;
                    }
                    else
                    {
                        Console.WriteLine("Candidate " + dc.getChar() + " found, but we are confident that this is NOT true");
                    }
                    
                }
            }

            if (confidence == 0){
                return 'O';
            }
            else
            {
                MessageBox.Show("Er is een karakter gevonden: " + possibleCandidate);
                return possibleCandidate;
            }
        }
        private Boolean lettersPresentInString(String query, String stringToTestAgainst)
        {
            Boolean lettersArePresent = true;
            foreach (char c in query)
            {
                if (stringToTestAgainst.IndexOf(c) == -1)
                {
                    return false;
                }
            }
            return lettersArePresent;
        }
        private Boolean pixelIsBlack(int x, int y)
        {
            Color c = _sourceImage.GetPixel((int)(breedtefactor * x), (int)(hoogtefactor * y));
            return ((c.R < 5) && (c.G < 5) && (c.B < 5)) ? true : false;
        }
    
    }
}
